home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tcl8.0 / compat / waitpid.c < prev   
Encoding:
C/C++ Source or Header  |  1997-08-15  |  4.6 KB  |  171 lines  |  [TEXT/CWIE]

  1. /* 
  2.  * waitpid.c --
  3.  *
  4.  *    This procedure emulates the POSIX waitpid kernel call on
  5.  *    BSD systems that don't have waitpid but do have wait3.
  6.  *    This code is based on a prototype version written by
  7.  *    Mark Diekhans and Karl Lehenbauer.
  8.  *
  9.  * Copyright (c) 1993 The Regents of the University of California.
  10.  * Copyright (c) 1994 Sun Microsystems, Inc.
  11.  *
  12.  * See the file "license.terms" for information on usage and redistribution
  13.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  14.  *
  15.  * SCCS: @(#) waitpid.c 1.9 96/02/15 12:08:26
  16.  */
  17.  
  18. #include "tclInt.h"
  19. #include "tclPort.h"
  20.  
  21. /*
  22.  * A linked list of the following structures is used to keep track
  23.  * of processes for which we received notification from the kernel,
  24.  * but the application hasn't waited for them yet (this can happen
  25.  * because wait may not return the process we really want).  We
  26.  * save the information here until the application finally does
  27.  * wait for the process.
  28.  */
  29.  
  30. typedef struct WaitInfo {
  31.     int pid;                /* Pid of process that exited. */
  32.     WAIT_STATUS_TYPE status;        /* Status returned when child exited
  33.                      * or suspended. */
  34.     struct WaitInfo *nextPtr;        /* Next in list of exited processes. */
  35. } WaitInfo;
  36.  
  37. static WaitInfo *deadList = NULL;    /* First in list of all dead
  38.                      * processes. */
  39.  
  40. /*
  41.  *----------------------------------------------------------------------
  42.  *
  43.  * waitpid --
  44.  *
  45.  *    This procedure emulates the functionality of the POSIX
  46.  *    waitpid kernel call, using the BSD wait3 kernel call.
  47.  *    Note:  it doesn't emulate absolutely all of the waitpid
  48.  *    functionality, in that it doesn't support pid's of 0
  49.  *    or < -1.
  50.  *
  51.  * Results:
  52.  *    -1 is returned if there is an error in the wait kernel call.
  53.  *    Otherwise the pid of an exited or suspended process is
  54.  *    returned and *statusPtr is set to the status value of the
  55.  *    process.
  56.  *
  57.  * Side effects:
  58.  *    None.
  59.  *
  60.  *----------------------------------------------------------------------
  61.  */
  62.  
  63. #ifdef waitpid
  64. #   undef waitpid
  65. #endif
  66.  
  67. int
  68. waitpid(pid, statusPtr, options)
  69.     int pid;            /* The pid to wait on.  Must be -1 or
  70.                  * greater than zero. */
  71.     int *statusPtr;        /* Where to store wait status for the
  72.                  * process. */
  73.     int options;        /* OR'ed combination of WNOHANG and
  74.                  * WUNTRACED. */
  75. {
  76.     register WaitInfo *waitPtr, *prevPtr;
  77.     int result;
  78.     WAIT_STATUS_TYPE status;
  79.  
  80.     if ((pid < -1) || (pid == 0)) {
  81.     errno = EINVAL;
  82.     return -1;
  83.     }
  84.  
  85.     /*
  86.      * See if there's a suitable process that has already stopped or
  87.      * exited. If so, remove it from the list of exited processes and
  88.      * return its information.
  89.      */
  90.  
  91.     for (waitPtr = deadList, prevPtr = NULL; waitPtr != NULL;
  92.         prevPtr = waitPtr, waitPtr = waitPtr->nextPtr) {
  93.     if ((pid != waitPtr->pid) && (pid != -1)) {
  94.         continue;
  95.     }
  96.     if (!(options & WUNTRACED) && (WIFSTOPPED(waitPtr->status))) {
  97.         continue;
  98.     }
  99.     result = waitPtr->pid;
  100.     *statusPtr = *((int *) &waitPtr->status);
  101.     if (prevPtr == NULL) {
  102.         deadList = waitPtr->nextPtr;
  103.     } else {
  104.         prevPtr->nextPtr = waitPtr->nextPtr;
  105.     }
  106.     ckfree((char *) waitPtr);
  107.     return result;
  108.     }
  109.  
  110.     /*
  111.      * Wait for any process to stop or exit.  If it's an acceptable one
  112.      * then return it to the caller;  otherwise store information about it
  113.      * in the list of exited processes and try again.  On systems that
  114.      * have only wait but not wait3, there are several situations we can't
  115.      * handle, but we do the best we can (e.g. can still handle some
  116.      * combinations of options by invoking wait instead of wait3).
  117.      */
  118.  
  119.     while (1) {
  120. #if NO_WAIT3
  121.     if (options & WNOHANG) {
  122.         return 0;
  123.     }
  124.     if (options != 0) {
  125.         errno = EINVAL;
  126.         return -1;
  127.     }
  128.     result = wait(&status);
  129. #else
  130.     result = wait3(&status, options, 0);
  131. #endif
  132.     if ((result == -1) && (errno == EINTR)) {
  133.         continue;
  134.     }
  135.     if (result <= 0) {
  136.         return result;
  137.     }
  138.  
  139.     if ((pid != result) && (pid != -1)) {
  140.         goto saveInfo;
  141.     }
  142.     if (!(options & WUNTRACED) && (WIFSTOPPED(status))) {
  143.         goto saveInfo;
  144.     }
  145.     *statusPtr = *((int *) &status);
  146.     return result;
  147.  
  148.     /*
  149.      * Can't return this info to caller.  Save it in the list of
  150.      * stopped or exited processes.  Tricky point: first check for
  151.      * an existing entry for the process and overwrite it if it
  152.      * exists (e.g. a previously stopped process might now be dead).
  153.      */
  154.  
  155.     saveInfo:
  156.     for (waitPtr = deadList; waitPtr != NULL; waitPtr = waitPtr->nextPtr) {
  157.         if (waitPtr->pid == result) {
  158.         waitPtr->status = status;
  159.         goto waitAgain;
  160.         }
  161.     }
  162.     waitPtr = (WaitInfo *) ckalloc(sizeof(WaitInfo));
  163.     waitPtr->pid = result;
  164.     waitPtr->status = status;
  165.     waitPtr->nextPtr = deadList;
  166.     deadList = waitPtr;
  167.  
  168.     waitAgain: continue;
  169.     }
  170. }
  171.